package com.ncbee.base.config.shiro.aop;

import com.ncbee.base.config.shiro.annotation.RequiresExtPermissions;
import org.apache.shiro.aop.MethodInvocation;
import org.apache.shiro.authz.AuthorizationException;
import org.apache.shiro.authz.annotation.Logical;
import org.apache.shiro.authz.aop.AuthorizingAnnotationHandler;
import org.apache.shiro.subject.Subject;

import java.lang.annotation.Annotation;

/**
 * @Author fengzirong
 * @DESC  拓展 RequiresExtPermissions注解功能
 * @Date 2018/12/13 11:21
 **/
public class ExtPermissionAnnotationHandler extends AuthorizingAnnotationHandler {
    public ExtPermissionAnnotationHandler() {
        super(RequiresExtPermissions.class);
    }

    @Override
    public void assertAuthorized(Annotation a) throws AuthorizationException {
    }

    /**
     * methodAnnotation==null：默认注解到类上则不拦截
     * 这里只对配置方法进行拦截
     * @param mi
     * @throws AuthorizationException
     */
    public void assertAuthorized(MethodInvocation mi) throws AuthorizationException {
        RequiresExtPermissions methodAnnotation = mi.getMethod().getAnnotation(RequiresExtPermissions.class);
        if(methodAnnotation==null){
            return;
        }
        String[] methodPerms = methodAnnotation.value();
        Subject subject = getSubject();
        if (methodPerms.length == 1) {
            RequiresExtPermissions classAnnotation = mi.getThis().getClass().getAnnotation(RequiresExtPermissions.class);
            if(null != classAnnotation) {
                String[] classPerms = classAnnotation.value();
                subject.checkPermission(classPerms[0] + methodPerms[0]);
            } else {
                subject.checkPermission(methodPerms[0]);
            }
            return;
        }
        if (Logical.AND.equals(methodAnnotation.logical())) {
            getSubject().checkPermissions(methodPerms);
            return;
        }
        if (Logical.OR.equals(methodAnnotation.logical())) {
            // Avoid processing exceptions unnecessarily - "delay" throwing the exception by calling hasRole first
            boolean hasAtLeastOnePermission = false;
            for (String permission : methodPerms) if (getSubject().isPermitted(permission)) hasAtLeastOnePermission = true;
            // Cause the exception if none of the role match, note that the exception message will be a bit misleading
            if (!hasAtLeastOnePermission) getSubject().checkPermission(methodPerms[0]);

        }
    }
}
